package com.example.gobang_system.websockethandler;

import com.example.gobang_system.common.pojo.CommonResult;
import com.example.gobang_system.common.pojo.UserInfo;
import com.example.gobang_system.common.util.JacksonUtil;
import com.example.gobang_system.service.match.Matcher;
import com.example.gobang_system.websockethandler.param.MatchParam;
import com.example.gobang_system.service.enums.MatchStatusEnum;
import com.example.gobang_system.service.manager.OnlineUserManager;
import com.example.gobang_system.websockethandler.result.MatchResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import static com.example.gobang_system.service.UserService.USER_INFO;
@Component
@Slf4j
public class MatchHandler extends TextWebSocketHandler {
    @Autowired
    private OnlineUserManager onlineUserManager;
    @Autowired
    private Matcher matcher;
    /**
     * 连接建立
     * @param session
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 从 session 中获取用户信息
        UserInfo userInfo = (UserInfo) session.getAttributes().get(USER_INFO);
        // 用户是否登录
        if (null == userInfo) {
            session.sendMessage(new TextMessage(JacksonUtil.writeValueAsString(
                    CommonResult.noLogin())));
            return;
        }
        // 判断用户是否处于在线状态
        if (null != onlineUserManager.getFromHall(userInfo.getUserId())) {
            session.sendMessage(new TextMessage(JacksonUtil.writeValueAsString(
                    CommonResult.repeatConnection())));
            return;
        }
        // 将用户设置为在线状态
        onlineUserManager.enterGameHall(userInfo.getUserId(), session);
        // 日志打印
        log.info("玩家 {} 进入游戏大厅", userInfo.getUserName());
    }

    /**
     * 处理匹配请求和停止匹配请求
     * @param session
     * @param message
     * @throws Exception
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 处理匹配请求和停止匹配请求
        UserInfo userInfo = (UserInfo) session.getAttributes().get(USER_INFO);
        // 用户是否登录
        if (null == userInfo) {
            session.sendMessage(new TextMessage(JacksonUtil.writeValueAsString(
                    CommonResult.noLogin())));
            return;
        }
        // 获取用户端发送的数据
        String payload = message.getPayload();
        // 将 JSON 字符串转化为 java 对象
        MatchParam matchParam = JacksonUtil.readValue(payload, MatchParam.class);
        if (MatchStatusEnum.START.name().equalsIgnoreCase(matchParam.getMessage())) {
            // 开始匹配
            matcher.addUserInfo(userInfo);
            session.sendMessage(new TextMessage(JacksonUtil.writeValueAsString(
                    CommonResult.success(new MatchResult(MatchStatusEnum.START.name())))));
        } else if (MatchStatusEnum.STOP.name().equalsIgnoreCase(matchParam.getMessage())) {
            // 结束匹配
            matcher.removeUserInfo(userInfo);
            session.sendMessage(new TextMessage(JacksonUtil.writeValueAsString(
                    CommonResult.success(new MatchResult(MatchStatusEnum.STOP.name())))));
        } else {
            session.sendMessage(new TextMessage(JacksonUtil.writeValueAsString(
                    CommonResult.fail(400, "错误的匹配信息"))));
        }
    }

    /**
     * 处理异常情况
     * @param session
     * @param exception
     * @throws Exception
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        // 打印错误信息
        log.error("匹配过程中出现异常: ", exception);
        logoutFromHall(session);
    }

    /**
     * 连接关闭
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        log.info("匹配连接断开, code: {}, reason: {}",
                status.getCode(), status.getReason());
        // 玩家下线
        logoutFromHall(session);
    }

    /**
     * 玩家离开游戏大厅
     * @param session
     */
    private void logoutFromHall(WebSocketSession session) {
        try {
            if (null == session) {
                return;
            }
            UserInfo userInfo = (UserInfo) session.getAttributes().get(USER_INFO);
            if (null == userInfo) {
                return;
            }
            // 存储的 session
            WebSocketSession onlineSession = onlineUserManager.getFromHall(userInfo.getUserId());
            // 判断获取到的 session 信息 与 onlineUserManager 中存储的 session 是否相同
            // 避免关闭多开时将玩家信息错误删除
            if (session == onlineSession) {
                // 将玩家从游戏大厅移除
                onlineUserManager.exitGameHall(userInfo.getUserId());
            }
            // 若玩家正在进行匹配，而 WebSocket 连接断开
            // 需要将其从匹配队列中移除
            matcher.removeUserInfo(userInfo);
            log.info("玩家 {} 从游戏大厅退出", userInfo.getUserName());
        } catch (Exception e) {
            log.warn("玩家 {} 退出游戏大厅时发生异常e: ", e);
        }
    }
}
